#include <rtthread.h>
#include <rtdevice.h>
#include <finsh.h>
#include "drv_codec.h"
#include "drv_clock.h"

/* 保存为wav文件 */
#define FILE_SAVE 0

#define kHaierAcYrw02Prefix 0xA6

#define kHaierAcYrw02SwingOff 0x0  //ɨ
#define kHaierAcYrw02SwingTop 0x1 
#define kHaierAcYrw02SwingMiddle 0x2   // Not available in heat mode.
#define kHaierAcYrw02SwingBottom 0x3   // Only available in heat mode.
#define kHaierAcYrw02SwingDown 0xA 
#define kHaierAcYrw02SwingAuto 0xC   // Airflow

#define kHaierAcYrw02FanHigh 0b001 
#define kHaierAcYrw02FanMed  0b010 
#define kHaierAcYrw02FanLow  0b011 
#define kHaierAcYrw02FanAuto 0b101   //

#define kHaierAcYrw02TurboOff 0x0 
#define kHaierAcYrw02TurboHigh 0x1 
#define kHaierAcYrw02TurboLow 0x2  //

#define kHaierAcYrw02Auto 0b000   // 0  //ģʽ
#define kHaierAcYrw02Cool 0b001   // 1
#define kHaierAcYrw02Dry  0b010   // 2
#define kHaierAcYrw02Heat 0b100   // 4
#define kHaierAcYrw02Fan  0b110   // 5+1

#define kHaierAcYrw02ButtonTempUp 0x0 
#define kHaierAcYrw02ButtonTempDown 0x1 
#define kHaierAcYrw02ButtonSwing 0x2 
#define kHaierAcYrw02ButtonFan 0x4 
#define kHaierAcYrw02ButtonPower 0x5 
#define kHaierAcYrw02ButtonMode 0x6 
#define kHaierAcYrw02ButtonHealth 0x7 
#define kHaierAcYrw02ButtonTurbo 0x8 
#define kHaierAcYrw02ButtonSleep 0xB 

typedef struct
{
	uint8_t Prefix; //A6
	uint8_t Swing;
	uint8_t power;
	uint8_t freq;  //38K
	uint8_t temp; //16-30
	uint8_t fan; //
	uint8_t Turbo;
	uint8_t mode;
	uint8_t sleep;
	uint8_t Button;
	uint8_t sum;
	uint16_t buff_size;
	uint8_t *buff;
} air_cfg_t;	

static air_cfg_t  air_haier_cfg;
#if FILE_SAVE
struct wav_header
{
    char  riff_id[4];              /* "RIFF" */
    int   riff_datasize;           /* RIFF chunk data size,exclude riff_id[4] and riff_datasize,total - 8 */
    char  riff_type[4];            /* "WAVE" */
    char  fmt_id[4];               /* "fmt " */
    int   fmt_datasize;            /* fmt chunk data size,16 for pcm */
    short fmt_compression_code;    /* 1 for PCM */
    short fmt_channels;            /* 1(mono) or 2(stereo) */
    int   fmt_sample_rate;         /* samples per second */
    int   fmt_avg_bytes_per_sec;   /* sample_rate * channels * bit_per_sample / 8 */
    short fmt_block_align;         /* number bytes per sample, bit_per_sample * channels / 8 */
    short fmt_bit_per_sample;      /* bits of each sample(8,16,32). */
    char  data_id[4];              /* "data" */
    int   data_datasize;           /* data chunk size,pcm_size - 44 */
};

static void wavheader_init(struct wav_header *header, int sample_rate, int channels, int datasize)
{
    memcpy(header->riff_id, "RIFF", 4);
    header->riff_datasize = datasize + 44 - 8;
    memcpy(header->riff_type, "WAVE", 4);
    memcpy(header->fmt_id, "fmt ", 4);
    header->fmt_datasize = 16;
    header->fmt_compression_code = 1;
    header->fmt_channels = channels;
    header->fmt_sample_rate = sample_rate;
    header->fmt_bit_per_sample = 16;
    header->fmt_avg_bytes_per_sec = header->fmt_sample_rate * header->fmt_channels * header->fmt_bit_per_sample / 8;
    header->fmt_block_align = header->fmt_bit_per_sample * header->fmt_channels / 8;
    memcpy(header->data_id, "data", 4);
    header->data_datasize = datasize;
}

static int fd;
static int fd_datasize;
#endif

static uint8_t expectedState[14] = {
		0xA6, 0x32, 0x00, 0x00, 0x40, 0x20, 0x00,
	0x20, 0x00, 0x00, 0x00, 0x00, 0x84, 0xdc};

rt_device_t snd = RT_NULL;
static int8_t *ir_tx_data;


void sound_ir_init(void)
{
    struct rt_audio_caps caps = {0};

    snd = rt_device_find("sound0");
    rt_device_open(snd, RT_DEVICE_FLAG_WRONLY);

    /* 设置采样率、通道、采样位数等音频参数信息 */
    caps.main_type               = AUDIO_TYPE_OUTPUT;                           /* 输出类型（播放设备 ）*/
    caps.sub_type                = AUDIO_DSP_PARAM;                             /* 设置所有音频参数信息 */
    caps.udata.config.samplerate = 192000;    /* 采样率 */
    caps.udata.config.channels   = 1;         /* 采样通道 */
    caps.udata.config.samplebits = 16;                                          /* 采样位数 */
    rt_device_control(snd, AUDIO_CTL_CONFIGURE, &caps);

    caps.main_type = AUDIO_TYPE_MIXER;
    caps.sub_type  = AUDIO_MIXER_VOLUME;
    caps.udata.value = 99;
    rt_device_control(snd, AUDIO_CTL_CONFIGURE, &caps);
}

void sound_ir_deinit(void)
{
    rt_device_close(snd);
}

/* send 38k*/
static void ir_enable_38k(void)
{
    int16_t pcm[6]={32767,32767,32767,-32767,-32767,-32767};
    for(int i=0; i<21; i++)//21
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }
}

static ir_disable_38k(void)
{
    int16_t pcm[5]={0,0,0,0,0};
    for(int i=0; i<21; i++)//21 560
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }

}

static ir_sync_enable_38k(void)//3ms
{
    int16_t pcm[6]={32767,32767,32767,-32767,-32767,-32767};
    for(int i=0; i<115; i++) 
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }
}

static ir_sync_disable_38k_3ms(void)//3ms
{
    int16_t pcm[5]={0,0,0,0,0};
    for(int i=0; i<115; i++)
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }
}

static ir_sync_disable_38k_4_5ms(void)//4.5ms
{
    int16_t pcm[5]={0,0,0,0,0};
    for(int i=0; i<172; i++)
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }
}

/* send 50ms */
static ir_sync_disable_38k_50ms(void)
{
    int16_t pcm[5]={0,0,0,0,0};
    for(int i=0; i<2560; i++)
    {
        rt_device_write(snd, 0, pcm, 10);
#if FILE_SAVE
        write(fd, pcm, 10);
        fd_datasize += 10;
#endif
    }
}


static void sound_ir_send_bit(int bit)
{
    ir_enable_38k();
    if(bit)
    {
        ir_disable_38k();
        ir_disable_38k();
    }
    ir_disable_38k();
}


int ir_haier_init(void)
{
	air_cfg_t *air_cfg = &air_haier_cfg;
	air_cfg->Prefix = kHaierAcYrw02Prefix;
	air_cfg->freq = 38;
	air_cfg->mode = kHaierAcYrw02Cool;
	air_cfg->fan = 0;
	air_cfg->power = 1;
	air_cfg->temp = 19;
	air_cfg->Swing = kHaierAcYrw02SwingAuto;//kHaierAcYrw02SwingMiddle;
	air_cfg->Turbo = kHaierAcYrw02TurboOff;
	air_cfg->sleep = 0;
	air_cfg->Button = kHaierAcYrw02ButtonTempUp;
	air_cfg->buff = expectedState;
	air_cfg->buff_size = sizeof(expectedState);
	return 0;
}

static uint8_t fan_mode[4] = {kHaierAcYrw02FanHigh, kHaierAcYrw02FanMed, kHaierAcYrw02FanLow, kHaierAcYrw02FanHigh};
static uint8_t ac_mode[4] = {kHaierAcYrw02Cool,kHaierAcYrw02Heat,kHaierAcYrw02Fan,0};

static void air_haier_config(uint8_t *buff, air_cfg_t *air_cfg)
{
	buff[0] = air_cfg->Prefix;
	buff[1] = air_cfg->Swing |(air_cfg->temp-16)<<4;
	buff[2] = 0;
	buff[3] = 0;
	buff[4] = air_cfg->power<<6;
	buff[5] = fan_mode[air_cfg->fan]<<5;
	buff[6] = air_cfg->Turbo<<5;
	buff[7] = air_cfg->mode<<5;
	buff[8] = air_cfg->sleep<<7;
	buff[9] = 0;
	buff[10] = 0;
	buff[11] = 0;
	buff[12] = air_cfg->Button;
	buff[13] = 0;
}

static uint8_t air_haier_sum(uint8_t *buff, uint16_t len)
{
	uint8_t sum = 0;
	uint16_t i;
	for(i=0; i<len-1; i++)
	{
		sum += buff[i];
	}
	buff[len-1] = sum;
	return sum;
}

static void ir_haier_send(uint8_t *ir_buff, uint16_t len)
{
	uint16_t i,k;
	int loop = 0;
	uint8_t buff[14];
#if FILE_SAVE
    struct wav_header header;
	
    fd_datasize = 0;
	fd = open("/mnt/sd0/music/ac_turnon_38k.wav", O_WRONLY | O_TRUNC);
#endif
	if(len != 14)
	{
		printf("ir_send  len erro\n");
		return;
	}
	memcpy(buff, ir_buff, 14);

	/* send 2 loop */
	while(loop++ < 2)
	{
		memcpy(buff, ir_buff, 14);
        ir_sync_disable_38k_50ms();
        ir_sync_enable_38k();
        ir_sync_disable_38k_3ms();
        ir_sync_enable_38k();
        ir_sync_disable_38k_4_5ms();
		
		for(i=0; i<len; i++)
		{
			for(k=0; k<8; k++)
			{
				if(buff[i]&0x80)
				{
                    sound_ir_send_bit(1);
				}
                else
                {
                    sound_ir_send_bit(0);
                }
				buff[i] <<= 1;
			}
		}
        sound_ir_send_bit(0);
        ir_sync_disable_38k_3ms();
	}
    ir_sync_disable_38k_50ms();
#if FILE_SAVE
    wavheader_init(&header, 192000, 1, fd_datasize);
    lseek(fd, 0, SEEK_SET);
    write(fd, &header, sizeof(struct wav_header));
    close(fd);
#endif
}

void ir_tx_set_temp(air_cfg_t *air_cfg, uint8_t temp)
{
	air_cfg->temp = temp;
}

void ir_tx_up_temp(air_cfg_t *air_cfg)
{
	if(air_cfg->temp++ >=30)
	{
		air_cfg->temp = 30;
	}
}

void ir_tx_down_temp(air_cfg_t *air_cfg)
{
	if(air_cfg->temp-- <=16)
	{
		air_cfg->temp = 16;
	}
}

void ir_tx_set_mode(air_cfg_t *air_cfg, uint8_t mode)
{
	air_cfg->mode = mode&0x07;
}

void ir_tx_set_fan(air_cfg_t *air_cfg)
{
	air_cfg->fan = (air_cfg->fan++ & 0x03);
}

void ir_tx_set_sleep(air_cfg_t *air_cfg, uint8_t sleep)
{
	air_cfg->sleep = sleep & 0x01;
}

void ir_tx_set_power(air_cfg_t *air_cfg, uint8_t power)
{
	air_cfg->power = power & 0x01;
}

void ir_tx_set_button(air_cfg_t *air_cfg, uint8_t Button)
{
	air_cfg->Button = Button&0x0f;
}


void ir_haier_on(void)
{
	air_cfg_t *air_cfg = &air_haier_cfg;
	ir_tx_set_power(air_cfg, 1);
	ir_tx_set_button(air_cfg, kHaierAcYrw02ButtonPower);
	air_haier_config(air_cfg->buff, air_cfg);
	air_haier_sum(air_cfg->buff, air_cfg->buff_size);	
	ir_haier_send(air_cfg->buff, air_cfg->buff_size);	
}

void ir_haier_off(void)
{
	air_cfg_t *air_cfg = &air_haier_cfg;
	ir_tx_set_power(air_cfg, 0);
	ir_tx_set_button(air_cfg, kHaierAcYrw02ButtonPower);
	air_haier_config(air_cfg->buff, air_cfg);
	air_haier_sum(air_cfg->buff, air_cfg->buff_size);	
	ir_haier_send(air_cfg->buff, air_cfg->buff_size);	
}

void et_ac_command(int cmd)
{
    air_cfg_t *air_cfg = &air_haier_cfg;
    int power, temp, mode, button;

    static int init = 0;
    if(init == 0)
    {
        ir_haier_init();
        init = 1;
    }

    power = (cmd>>6) & 1;
    temp = ((cmd>>0) & 15)+16;
    mode = ac_mode[(cmd>>4) & 3];

    rt_kprintf("pwoer %d temp %d mode %d\n", power, temp, mode);

    if(power != air_cfg->power)
    {
        air_cfg->power = power;
        button = kHaierAcYrw02ButtonPower;
    }

    if(temp != air_cfg->temp)
    {
        if(temp < air_cfg->temp)
        {
            button = kHaierAcYrw02ButtonTempDown;
        }
        else 
        {
            button = kHaierAcYrw02ButtonTempUp;
        }
        air_cfg->temp = temp; 
    }
    if(mode != air_cfg->mode)
    {
        switch (mode)
        {
        case kHaierAcYrw02Cool:
            button = kHaierAcYrw02ButtonTempUp;
            break;
        case kHaierAcYrw02Heat:
            button = kHaierAcYrw02ButtonHealth;
            break;
        case kHaierAcYrw02Fan:
            button = kHaierAcYrw02ButtonFan;
            break;
        
        default:
            break;
        }
        air_cfg->mode = mode; 
    }

    sound_ir_init();

    rt_kprintf("ir_send start\n");
    
    

    ir_tx_set_button(air_cfg, button);
	air_haier_config(air_cfg->buff, air_cfg);
	air_haier_sum(air_cfg->buff, air_cfg->buff_size);	
	ir_haier_send(air_cfg->buff, air_cfg->buff_size);

    rt_kprintf("ir_send end\n");

    sound_ir_deinit();
}

static void sound_ir_thread_entry(void *parameter)
{
    int offset = 0;
    sound_ir_init();

    rt_kprintf("ir_send start\n");
    ir_haier_init();
    ir_haier_on();

    rt_kprintf("ir_send end\n");

    sound_ir_deinit();
}
/* 192k 1ms 192 192/5=  */ 
// 550us-1600us 550us-550us
void sound_ir_demo(void)
{
    rt_thread_t tid = RT_NULL;

    tid = rt_thread_create("sound_ir_thread",
                            sound_ir_thread_entry,
                            RT_NULL,
                            1024 * 32,
                            27,
                            10);
    if (tid != RT_NULL)
        rt_thread_startup(tid);
}
MSH_CMD_EXPORT(sound_ir_demo, sound_ir_demo);


